﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureRoofProfileUsedModelLineUtils.h"
#include "IModelLine.h"
#include "IExternalDatas.h"
#include "ModelLineUsedRoofSlopeData.h"
#include "IGenericElement.h"
#include "ICurve3d.h"
#include "IElementStatus.h"
#include "IPolyCurve.h"
#include "IPlaneCurve3d.h"
#include "IPolygon.h"
#include "ICurve2d.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

EXPOSE_DEBUG_MODE(SetModelLineNotCuttableByViewRange);

// 模型线带有坡度信息data
const std::wstring ED_KEY_MODEL_LINE_USED_ROOF_SLOPE = L"ModelLineUsedRoofSlopeDataKey";

IModelLine* gcmp::StructureRoofProfileUsedModelLineUtils::CreateModelLineUsedForRoofProfile(IDocument* pDoc, OwnerPtr<ICurve3d> opCurve)
{
    // 基于三维曲线创建轮廓线
    IModelLine* pModelLine = IModelLine::Create(pDoc, TransferOwnership(opCurve));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelLine, L"pIModelLine创建失败",L"GDMPLab",L"2024-03-30");

    // 注册外部数据，标记轮廓线已经被使用
    pModelLine->GetExternalDatas()->RegisterExternalData(ED_KEY_MODEL_LINE_USED_ROOF_SLOPE,
        NEW_AS_OWNER_PTR(ModelLineUsedRoofSlopeData, pDoc, pModelLine->GetOwnerElement()->GetElementId()));

    if (DEBUG_MODE(SetModelLineNotCuttableByViewRange))
    {
        // 用作轮廓线的模型线设置为不被视图范围裁剪
        pModelLine->SetCuttableByModelViewRange(false);
    }

    return pModelLine;
}

bool gcmp::StructureRoofProfileUsedModelLineUtils::GenerateModelLinesFromPolygon(IDocument* pDoc, const IPolygon* pPolygon, const ElementId& associatedPlaneId, std::vector<IModelLine*>& profileModelLines)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pPolygon, L"pPolygon为空",L"GDMPLab",L"2024-03-30");

    // 生成轮廓线集合
    Coordinate3d planeCoord = Coordinate3d::CreateFromAxis(Vector3d::Create(0, 0, 0), Vector3d::Create(1, 0, 0), Vector3d::Create(0, 1, 0));
    int polyCurveNum = pPolygon->GetPolyCurveCount();
    for (int i = 0; i < polyCurveNum; i++)
    {
        OwnerPtr<IPolyCurve> opPolyCurve = pPolygon->GetPolyCurve(i);
        if (!opPolyCurve->IsClosed())
        {
            //只取封闭的轮廓
            continue;
        }
        std::vector<OwnerPtr<ICurve2d>> curve2dList;
        bool bOk = opPolyCurve->GetAllCurves(curve2dList);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bOk, L"获取curve2dList失败",L"GDMPLab",L"2024-03-30");

        FOR_EACH(curve2d, curve2dList)
        {
            OwnerPtr<IPlaneCurve3d> opCurve3d = IPlaneCurve3d::Create(planeCoord, TransferOwnership(curve2d));
            DBG_WARN_AND_RETURN_FALSE_UNLESS(opCurve3d, L"opCurve3d为空",L"GDMPLab",L"2024-03-30");

            IModelLine* pModelLine = gcmp::StructureRoofProfileUsedModelLineUtils::CreateModelLineUsedForRoofProfile(pDoc, TransferOwnership(opCurve3d));
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelLine, L"pModelLine为空",L"GDMPLab",L"2024-03-30");

            if (DEBUG_MODE(SetModelLineNotCuttableByViewRange))
            {
                // 用作轮廓线的模型线设置为不被视图范围裁剪
                pModelLine->SetCuttableByModelViewRange(false);
            }

            profileModelLines.push_back(pModelLine);
        }
    }
    DBG_WARN_AND_RETURN_FALSE_UNLESS(!profileModelLines.empty(), L"生成轮廓线集合失败",L"GDMPLab",L"2024-03-30");

    return true;
}

bool StructureRoofProfileUsedModelLineUtils::IsModelLineUsedForRoofProfile(const IModelLine* pModelLine)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelLine, L"pModelLine为空",L"GDMPLab",L"2024-03-30");

    if (pModelLine->GetExternalDatas()->GetAllExternalDatas().empty())
    {
        return false;
    }
    else
    {
        if (pModelLine->GetExternalDatas()->FindExternalData(ED_KEY_MODEL_LINE_USED_ROOF_SLOPE) != nullptr)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

bool StructureRoofProfileUsedModelLineUtils::IsModelLineUsedForRoofProfile(const IElement* pElement)
{
    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement);
    if (!pGenericElement)
    {
        return false;
    }

    const IModelLine* pModelLine = quick_cast<IModelLine>(pGenericElement->GetExternalObject());
    if (!pModelLine)
    {
        return false;
    }

    return IsModelLineUsedForRoofProfile(pModelLine);
}

bool StructureRoofProfileUsedModelLineUtils::GetRoofProfileModelLinesInCurrentDocument(const IDocument* pDoc, std::vector<IModelLine*>& profileCurves)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    std::vector<IModelLine*> modelLines = IModelLine::GetAllModelLines(pDoc);
    FOR_EACH(pModelLine, modelLines)
    {
        const IElement* pElement = pModelLine->GetOwnerElement();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        if (pElement->GetStatus()->IsVisible() && IsModelLineUsedForRoofProfile(pModelLine))
        {
            profileCurves.push_back(pModelLine);
        }
    }

    return true;
}

bool StructureRoofProfileUsedModelLineUtils::SetAssociatedInstanceIdForModelLines(std::vector<IModelLine*> profileCurves, ElementId instanceId)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(profileCurves.size() > 0, L"传入的轮廓为空",L"GDMPLab",L"2024-03-30");

    FOR_EACH(pModelLine, profileCurves)
    {
        if (IsModelLineUsedForRoofProfile(pModelLine))
        {
            auto pData = pModelLine->GetExternalDatas()->FindExternalData(ED_KEY_MODEL_LINE_USED_ROOF_SLOPE);

            ModelLineUsedRoofSlopeData* pProfileData = quick_cast<ModelLineUsedRoofSlopeData>(pData);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pProfileData, L"pProfileData为空",L"GDMPLab",L"2024-03-30");
            pProfileData->SetInstanceId(instanceId);
        }
        else
        {
            DBG_WARN(L"当前模型线不是用于绘制屋顶轮廓的，请检查轮廓信息",L"GDMPLab",L"2024-03-30");
        }
    }

    return true;
}
